#include <iostream>
#include <string>
#include <memory>

// 建造者模式主要基于四个核⼼类实现：
// • 抽象产品类：
// • 具体产品类：⼀个具体的产品对象类
// • 抽象Builder类：创建⼀个产品对象所需的各个部件的抽象接⼝
// • 具体产品的Builder类：实现抽象接⼝，构建各个部件

// • 指挥者Director类：统⼀组建过程，提供给调⽤者使⽤，通过指挥者来构造产品(不同的组装顺序可能产生不同的产品, 或者为产品对象添加新的功能类)

// 抽象产品：电脑
class Computer
{
public:
    Computer() {}

    // 模拟电脑的不同组件
    void setBoard(const std::string board)
    {
        _board = board;
    }
    void setDisplay(const std::string display)
    {
        _display = display;
    }
    void show()
    {
        std::string computer = "Computer:{\n";
        computer += "\tboard=" + _board + ",\n";
        computer += "\tdisplay=" + _display + ",\n";
        computer += "\tOs=" + _os + ",\n";
        computer += "}\n";

        std::cout << computer << std::endl;
    }
    virtual void setOs() = 0; // 不同电脑的OS可能不同

protected:
    std::string _board;
    std::string _display;
    std::string _os;
};

// 具体产品：苹果电脑
class MacBook : public Computer
{
public:
    void setOs() override
    {
        _os = "Mac Os x12";
    }
};

// 抽象Builder类
class Builder
{
public:
    virtual void BuildBoard(const std::string board) = 0;
    virtual void BuildDisplay(const std::string display) = 0;
    virtual void BuildOs() = 0;
    virtual std::shared_ptr<Computer> Build() = 0;
};

// 具体builder类 : 建造苹果电脑的类
class MacBookBuilder : public Builder
{
public:
    MacBookBuilder()
        : _computer(new MacBook)
    {
    }

    // 开始组装电脑
    virtual void BuildBoard(const std::string board)
    {
        _computer->setBoard(board);
    }
    virtual void BuildDisplay(const std::string display)
    {
        _computer->setDisplay(display);
    }

    virtual void BuildOs()
    {
        _computer->setOs();
    }

    virtual std::shared_ptr<Computer> Build()
    {
        return _computer;
    }

private:
    std::shared_ptr<Computer> _computer;
};

// 指挥者Director类
class Director
{
public:
    Director(Builder *builder)
        : _builder(builder)
    {
    }

    // 指挥者控制组装的顺序
    void construct(const std::string &board, const std::string &display)
    {
        _builder->BuildBoard(board);     // 先装主板
        _builder->BuildDisplay(display); // 再装显示器
        _builder->BuildOs();             // 最后是OS
    }

private:
    std::shared_ptr<Builder> _builder;
};

int main()
{
    Builder *builder = new MacBookBuilder();//指明我要建造的是苹果电脑
    std::shared_ptr<Director> pd(new Director(builder));//创建指挥者，由指挥者来控制具体的组装s顺序
    pd->construct("华硕", "三星显示器"); // 组装

    std::shared_ptr<Computer> pc = builder->Build();//建造完成之后返回给用户
    pc->show();//多态

    return 0;
}

//抽象类的具体类的关系优点类似与声明和定义，唯一需要注意的一点是搞清楚多态